package com.zpp.gobang.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zpp.gobang.game.*;
import com.zpp.gobang.model.User;
import com.zpp.gobang.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class GameAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private UserService userService;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //客户端连接房间后，服务器返回的响应
        GameReadyResponse response = new GameReadyResponse();

        //1.先获取用户信身份息 从session中获取
        User user = (User) session.getAttributes().get("user");
        //处理用户未登录
        if(user == null){
            response.setOk(false);
            response.setReason("用户未登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //2.判断当前用户是否已经进入游戏房间
        Room room = roomManager.getRoomByUserId(user.getUserId());
        //处理用户未进入房间,未匹配到玩家
        if(room == null) {
            response.setOk(false);
            response.setReason("用户尚未匹配到");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        //3.判断当前用户是不是多开，已经在别的地方开了游戏了
        if(onlineUserManager.getFromGameHall(user.getUserId()) != null ||
            onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
            response.setOk(true);
            response.setMessage("repeatLogin");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        //处理完异常情况
        //设置玩家上线
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        synchronized (room) {
            //把两个玩家加入到游戏房间中
            if(room.getUser1() == null){
                //第一个玩家加入房间
                room.setUser1(user);
                room.setWhiteUser(user.getUserId());
                System.out.println("玩家1：" + user.getUsername() + "已经准备就绪");
                return;
            }

            if(room.getUser2() == null){
                room.setUser2(user);
                System.out.println("玩家2：" + user.getUsername() + "已经准备就绪");

                //此时两个玩家都已经加入成功，服务器需要给这两个玩家都返回websocket响应
                //通知玩家1
                noticeGameReady(room,room.getUser1(),room.getUser2());
                //通知玩家2
                noticeGameReady(room,room.getUser2(),room.getUser1());
                return;
            }
        }

        //如果又有玩家尝试连接房间，就提示报错
        response.setOk(false);
        response.setReason("当前房间已满，您不能加入");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setMessage("gameReady");
        response.setOk(true);
        response.setReason("");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(thisUser.getUserId());
        response.setThatUserId(thatUser.getUserId());
        response.setWhiteUser(room.getWhiteUser());
        response.setThatUserName(thatUser.getUsername());

        //把当前的响应数据传回给对应玩家
        WebSocketSession session = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if(user == null) {
            System.out.println("[handleTextMessage] : 用户未登录");
            return;
        }

        //根据用户id获取游戏房间
        Room room = roomManager.getRoomByUserId(user.getUserId());
        //通过room对象来处理具体的请求
        String payload = message.getPayload();
        room.putChess(objectMapper.readValue(payload,GameRequest.class));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //玩家下线，从OnlineUserManager中删除

        User user= (User) session.getAttributes().get("user");
        if(user == null) {
            //在断开连接后，不给客户端响应了
            return;
        }

        //判断要下线的用户是否是多开用户下线，防止误删
        WebSocketSession tmpSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if(tmpSession == session){  //避免在多开的情况下，第二个用户的退出把第一个用户也退出了
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        System.out.println("游戏连接异常  用户： "+user.getUsername() +"下线");

        noticeThatUserWin(user);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //玩家下线，从OnlineUserManager中删除

        User user= (User) session.getAttributes().get("user");
        if(user == null) {
            //在断开连接后，不给客户端响应了
            return;
        }

        //判断要下线的用户是否是多开用户下线，防止误删
        WebSocketSession tmpSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if(tmpSession == session){  //避免在多开的情况下，第二个用户的退出把第一个用户也退出了
            onlineUserManager.exitGameRoom(user.getUserId());
        }
        System.out.println("退出游戏房间  用户： "+user.getUsername() +"下线");

        //玩家下线，通知对手获胜
        noticeThatUserWin(user);
    }

    private void noticeThatUserWin(User user) throws IOException {
        //1.根据user找到玩家所在房间
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if(room == null) {
            //游戏房间已经不存在，无需通知
            System.out.println("当前房间已经被释放了，无需通知对手");
            return;
        }

        //2.根据房间找到对手
        User thatUser = user == room.getUser1() ? room.getUser2() : room.getUser1();
        //3.找到读对手在线状态
        WebSocketSession session = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if(session == null){
            //对手也已经下线了就不做处理了
            System.out.println("对手已经下线，无需通知");
            return;
        }

        //构造响应通知对手获胜
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setWinner(thatUser.getUserId());
        response.setUserId(thatUser.getUserId());

        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

        //更新玩家分数
        userService.winUSer(thatUser.getUserId());
        userService.loseUser(user.getUserId());

        //释放房间对象  避免内存那泄露
        roomManager.remove(room.getRoomId(), room.getUser1().getUserId(),room.getUser2().getUserId());
    }
}
